home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dterm / dterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1985-02-26  |  21.9 KB  |  1,088 lines

  1. /* @(#)dterm.c    1.14    (Berkeley)    2/26/85"
  2.  *
  3.  *    Converts ditroff output to text on a terminal.  It is NOT meant to
  4.  *    produce readable output, but is to show one how one's paper is (in
  5.  *    general) formatted - what will go where on which page.
  6.  *
  7.  *    options:
  8.  *
  9.  *      -hn    set horizontal resolution to n (in characters per inch;
  10.  *        default is 10.0).
  11.  *
  12.  *      -vn    set vertical resolution (default is 6.0).
  13.  *
  14.  *      -ln    set maximum output line-length to n (default is 79).
  15.  *
  16.  *    -olist    output page list - as in troff.
  17.  *
  18.  *      -c    continue at end of page.  Default is to stop at the end
  19.  *        of each page, print "dterm:" and wait for a command.
  20.  *        Type ? to get a list of available commands.
  21.  *
  22.  *      -m    print margins.  Default action is to cut printing area down
  23.  *        to only the part of the page with information on it.
  24.  *
  25.  *      -a    make the output readable - i.e. print like a "troff -a" with
  26.  *        no character overlap, and one space 'tween words
  27.  *
  28.  *      -L    put a form feed (^L) at the end of each page
  29.  *
  30.  *      -w    sets h = 20, v = 12, l = 131, also sets -c, -m and -L to allow
  31.  *        for extra-wide printouts on the printer.
  32.  *
  33.  *    -fxxx    get special character definition file "xxx".  Default is
  34.  *        FONTDIR/devter/specfile.
  35.  */
  36.  
  37.  
  38. #include    <stdio.h>
  39. #include    <ctype.h>
  40. #include    <math.h>
  41.  
  42.  
  43. #define    FATAL        1
  44. #define    PGWIDTH        266        /* WAY too big - for good measure */
  45. #define    PGHEIGHT    220
  46. #define LINELEN        78
  47. #define SPECFILE    "devter/specfile"
  48. #ifndef FONTDIR
  49. #define FONTDIR        "/usr/lib/font"
  50. #endif
  51.  
  52. #define hgoto(n)    hpos = n
  53. #define vgoto(n)    vpos = n
  54. #define hmot(n)        hpos += n
  55. #define vmot(n)        vpos += n
  56.  
  57. #define    sgn(n)        ((n > 0) ? 1 : ((n < 0) ? -1 : 0))
  58. #define    abs(n)        ((n) >= 0 ? (n) : -(n))
  59. #define    max(x,y)    ((x) > (y) ? (x) : (y))
  60. #define    min(x,y)    ((x) < (y) ? (x) : (y))
  61. #define sqr(x)        (long int)(x)*(x)
  62.  
  63.  
  64. char    SccsId [] = "@(#)dterm.c    1.14    (Berkeley)    2/26/85";
  65.  
  66. char    **spectab;        /* here go the special characters */
  67. char    specfile[100] = FONTDIR;/* place to look up special characters */
  68. char    *malloc();
  69. char    *operand();
  70.  
  71. int     keepon    = 0;    /* flags:  Don't stop at the end of each page? */
  72. int    clearsc = 0;        /* Put out form feed at each page? */
  73. int    output    = 0;        /* Do we do output at all? */
  74. int    nolist    = 0;        /* Output page list if > 0 */
  75. int    margin    = 0;        /* Print blank margins? */
  76. int    ascii    = 0;        /* make the output "readable"? */
  77. int    olist[20];        /* pairs of page numbers */
  78.  
  79. float    hscale    = 10.0;        /* characters and lines per inch for output */
  80. float    vscale    = 6.0;        /*    device (defaults are for printer) */
  81. FILE    *fp = stdin;        /* input file pointer */
  82.  
  83. char    pagebuf[PGHEIGHT][PGWIDTH];
  84. int    minh    = PGWIDTH;
  85. int    maxh    = 0;
  86. int    minv    = PGHEIGHT;
  87. int    maxv    = 0;
  88. int    linelen = LINELEN;
  89.  
  90. int    hpos;        /* horizontal position to be next (left = 0) */
  91. int    vpos;        /* current vertical position (down positive) */
  92.  
  93. int    np;        /* number of pages seen */
  94. int    npmax;        /* high-water mark of np */
  95. int    pgnum[40];    /* their actual numbers */
  96. long    pgadr[40];    /* their seek addresses */
  97.  
  98. int    DP;            /* step size for drawing */
  99. int    maxdots    = 3200;        /* maximum number of dots in an object */
  100.  
  101.  
  102.  
  103. main(argc, argv)
  104. int argc;
  105. char **argv;
  106. {
  107.     strcat(specfile, "/");
  108.     strcat(specfile, SPECFILE);
  109.     while (--argc > 0 && **++argv == '-') {
  110.         switch ((*argv)[1]) {
  111.         case 'f':        /* special character filepath */
  112.             strncpy(specfile, operand(&argc, &argv), 100);
  113.             break;
  114.         case 'l':        /* output line length */
  115.             linelen = atoi(operand(&argc, &argv)) - 1;
  116.             break;
  117.         case 'h':        /* horizontal scale (char/inch) */
  118.             hscale = atof(operand(&argc, &argv));
  119.             break;
  120.         case 'v':        /* vertical scale (char/inch) */
  121.             vscale = atof(operand(&argc, &argv));
  122.             break;
  123.         case 'o':        /* output list */
  124.             outlist(operand(&argc, &argv));
  125.             break;
  126.         case 'c':        /* continue at endofpage */
  127.             keepon = !keepon;
  128.             break;
  129.         case 'm':        /* print margins */
  130.             margin = !margin;
  131.             break;
  132.         case 'a':        /* readable mode */
  133.             ascii = !ascii;
  134.             break;
  135.         case 'L':        /* form feed after each page */
  136.             clearsc = !clearsc;
  137.             break;
  138.          case 'w':        /* "wide" printer format */
  139.             hscale = 16.0;
  140.             vscale = 9.6;
  141.             linelen = 131;
  142.             keepon = 1;
  143.             clearsc = 1;
  144.             break;
  145.         }
  146.     }
  147.  
  148.     if (argc < 1)
  149.         conv(stdin);
  150.     else
  151.         while (argc--) {
  152.             if (strcmp(*argv, "-") == 0)
  153.                 fp = stdin;
  154.             else if ((fp = fopen(*argv, "r")) == NULL)
  155.                 error(FATAL, "can't open %s", *argv);
  156.             conv(fp);
  157.             fclose(fp);
  158.             argv++;
  159.         }
  160.     done();
  161. }
  162.  
  163.  
  164. /*----------------------------------------------------------------------------*
  165.  | Routine:    char  * operand (& argc,  & argv)
  166.  |
  167.  | Results:    returns address of the operand given with a command-line
  168.  |        option.  It uses either "-Xoperand" or "-X operand", whichever
  169.  |        is present.  The program is terminated if no option is present.
  170.  |
  171.  | Side Efct:    argc and argv are updated as necessary.
  172.  *----------------------------------------------------------------------------*/
  173.  
  174. char *operand(argcp, argvp)
  175. int * argcp;
  176. char ***argvp;
  177. {
  178.     if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
  179.     if ((--*argcp) <= 0) {            /* operand next word */
  180.         fprintf (stderr, "command-line option operand missing.\n");
  181.         exit(1);
  182.     }
  183.     return(*(++(*argvp)));            /* no operand */
  184. }
  185.  
  186.  
  187. outlist(s)    /* process list of page numbers to be printed */
  188. char *s;
  189. {
  190.     int n1, n2, i;
  191.  
  192.     nolist = 0;
  193.     while (*s) {
  194.         n1 = 0;
  195.         if (isdigit(*s))
  196.             do
  197.                 n1 = 10 * n1 + *s++ - '0';
  198.             while (isdigit(*s));
  199.         else
  200.             n1 = -9999;
  201.         n2 = n1;
  202.         if (*s == '-') {
  203.             s++;
  204.             n2 = 0;
  205.             if (isdigit(*s))
  206.                 do
  207.                     n2 = 10 * n2 + *s++ - '0';
  208.                 while (isdigit(*s));
  209.             else
  210.                 n2 = 9999;
  211.         }
  212.         olist[nolist++] = n1;
  213.         olist[nolist++] = n2;
  214.         if (*s != '\0')
  215.             s++;
  216.     }
  217.     olist[nolist] = 0;
  218. }
  219.  
  220.  
  221. in_olist(n)    /* is n in olist? */
  222. int n;
  223. {
  224.     int i;
  225.  
  226.     if (nolist == 0)
  227.         return(1);    /* everything is included */
  228.     for (i = 0; i < nolist; i += 2)
  229.         if (n >= olist[i] && n <= olist[i+1])
  230.             return(1);
  231.     return(0);
  232. }
  233.  
  234.  
  235. conv(fp)
  236. register FILE *fp;
  237. {
  238.     register int c;
  239.     int m, n, i, n1, m1;
  240.     char str[100], buf[300];
  241.  
  242.     while ((c = getc(fp)) != EOF) {
  243.         switch (c) {
  244.         case '\n':    /* when input is text */
  245.         case '\t':
  246.         case ' ':
  247.         case 0:
  248.             break;
  249.  
  250.         case '0': case '1': case '2': case '3': case '4':
  251.         case '5': case '6': case '7': case '8': case '9':
  252.                 /* two motion digits plus a character */
  253.             if (ascii) {
  254.                 hmot((int)hscale);
  255.                 getc(fp);
  256.             } else {
  257.                 hmot((c-'0')*10 + getc(fp)-'0');
  258.             }
  259.             put1(getc(fp));
  260.             break;
  261.  
  262.         case 'c':    /* single ascii character */
  263.             put1(getc(fp));
  264.             break;
  265.  
  266.         case 'C':    /* funny character */
  267.             fscanf(fp, "%s", str);
  268.             put1s(str);
  269.             break;
  270.  
  271.         case 't':    /* straight text */
  272.             fgets(buf, sizeof(buf), fp);
  273.             t_text(buf);
  274.             break;
  275.  
  276.         case 'D':    /* draw function */
  277.             fgets(buf, sizeof(buf), fp);
  278.             switch (buf[0]) {
  279.             case 'l':    /* draw a line */
  280.                 sscanf(buf+1, "%d %d", &n, &m);
  281.                 drawline(n, m);
  282.                 break;
  283.             case 'c':    /* circle */
  284.                 sscanf(buf+1, "%d", &n);
  285.                 drawcirc(n);
  286.                 break;
  287.             case 'e':    /* ellipse */
  288.                 sscanf(buf+1, "%d %d", &m, &n);
  289.                 drawellip(m, n);
  290.                 break;
  291.             case 'a':    /* arc */
  292.                 sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
  293.                 drawarc(n, m, n1, m1);
  294.                 break;
  295.             case 'q':    /* versatec polygon - ignore */
  296.                 while (buf[strlen(buf) - 1] != '\n')
  297.                     if (fgets(buf, sizeof(buf), fp) == NULL)
  298.                     error(FATAL,"unexpected end of input");
  299.                 break;
  300.             case 'P':    /* unbordered */
  301.             case 'p':    /* polygon */
  302.                 sscanf(buf+1, "%d", &n);
  303.                 n = 1;
  304.                 while(buf[n++] == ' ');
  305.                 while(isdigit(buf[n])) n++;
  306.                 drawwig(buf+n, 1);
  307.                 break;
  308.             case 'g':    /* "gremlin" curve */
  309.             case '~':    /* wiggly line */
  310.                 drawwig(buf+1, 0);
  311.                 break;
  312.             case 't':    /* thickness - not important */
  313.             case 's':    /* style - not important */
  314.                 break;
  315.             default:
  316.                 error(FATAL,"unknown drawing command %s\n",buf);
  317.                 break;
  318.             }
  319.             break;
  320.         case 'i':    /* stipple pattern request - ignored */
  321.         case 's':    /* point size - ignored */
  322.             fscanf(fp, "%d", &n);
  323.             break;
  324.  
  325.         case 'f':    /* font request - ignored */
  326.             fscanf(fp, "%s", str);
  327.             break;
  328.  
  329.         case 'H':    /* absolute horizontal motion */
  330.             fscanf(fp, "%d", &n);
  331.             hgoto(n);
  332.             break;
  333.  
  334.         case 'h':    /* relative horizontal motion */
  335.             fscanf(fp, "%d", &n);
  336.             hmot(n);
  337.             break;
  338.  
  339.         case 'w':    /* word space */
  340.             if (ascii) {
  341.                 hmot((int)hscale);
  342.             }
  343.             break;
  344.  
  345.         case 'V':    /* absolute vertical motion */
  346.             fscanf(fp, "%d", &n);
  347.             vgoto(n);
  348.             break;
  349.  
  350.         case 'v':    /* relative vertical motion */
  351.             fscanf(fp, "%d", &n);
  352.             vmot(n);
  353.             break;
  354.  
  355.         case 'p':    /* new page */
  356.             fscanf(fp, "%d", &n);
  357.             t_page(n);
  358.             break;
  359.  
  360.         case 'P':    /* new span (ignored) */
  361.             fscanf(fp, "%d", &n);
  362.             break;
  363.  
  364.         case 'n':    /* end of line */
  365.             hpos = 0;
  366.         case '#':    /* comment */
  367.             while (getc(fp) != '\n')
  368.                 ;
  369.             break;
  370.  
  371.         case 'x':    /* device control */
  372.             devcntrl(fp);
  373.             break;
  374.  
  375.         default:
  376.             error(!FATAL, "unknown input character %o %c\n", c, c);
  377.             done();
  378.         }
  379.     }
  380. }
  381.  
  382.  
  383. devcntrl(fp)    /* interpret device control functions */
  384. FILE *fp;
  385. {
  386.     int c, n;
  387.     char str[20];
  388.  
  389.     fscanf(fp, "%s", str);
  390.     switch (str[0]) {    /* crude for now */
  391.     case 'i':    /* initialize */
  392.         t_init(0);
  393.         break;
  394.     case 'r':    /* resolution assumed when prepared */
  395.         fscanf(fp, "%d", &n);
  396.         hscale = (float) n / hscale;
  397.         vscale = (float) n / vscale;
  398.         DP = min (hscale, vscale);    /* guess the drawing */
  399.         DP = max (DP, 1);        /* resolution */
  400.         break;
  401.     case 'f':    /* font used */
  402.     case 'T':    /* device name */
  403.     case 't':    /* trailer */
  404.     case 'p':    /* pause -- can restart */
  405.     case 's':    /* stop */
  406.         break;
  407.     }
  408.     while (getc(fp) != '\n')    /* skip rest of input line */
  409.         ;
  410. }
  411.  
  412.         /* error printing routine - first argument is a "fatal" flag */
  413. error(f, s, a1, a2, a3, a4, a5, a6, a7) {
  414.     fprintf(stderr, "dterm: ");
  415.     fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
  416.     fprintf(stderr, "\n");
  417.     if (f) exit(1);
  418. }
  419.  
  420.  
  421. t_init(reinit)    /* initialize device */
  422. int reinit;
  423. {
  424.     register int i;
  425.     register int j;
  426.     register FILE *fp;    /* file to look up special characters */
  427.     register char *charptr;    /* string pointer to step through specials */
  428.     register char *tabptr;    /* string pointer for spectab setting */
  429.     char specials[5000];    /* intermediate input buffer (made bigger */
  430.                 /*   than we'll EVER use... */
  431.  
  432.  
  433.     fflush(stdout);
  434.     hpos = vpos = 0;
  435.     for (i = 0; i < PGHEIGHT; i++)
  436.         for (j = 0; j < PGWIDTH; j++)
  437.             pagebuf[i][j] = ' ';
  438.     minh = PGWIDTH;
  439.     maxh = 0;
  440.     minv = PGHEIGHT;
  441.     maxv = 0;
  442.  
  443.     if (reinit) return;        /* if this is the first time, read */
  444.                     /* special character table file. */
  445.     if ((fp = fopen (specfile, "r")) != NULL) {
  446.         charptr = &specials[0];
  447.         for (i = 2; fscanf(fp, "%s", charptr) != EOF; i++) {
  448.         charptr += strlen(charptr) + 1;
  449.         }
  450.         fclose(fp);
  451.         *charptr++ = '\0';            /* ending strings */
  452.         *charptr++ = '\0';
  453.                         /* allocate table */
  454.         spectab = (char **) malloc(i * sizeof(char*));
  455.         spectab[0] = tabptr = malloc(j = (int) (charptr - &specials[0]));
  456.  
  457.                         /* copy whole table */
  458.         for (charptr = &specials[0]; j--; *tabptr++ = *charptr++);
  459.  
  460.         tabptr = spectab[0];        /* set up pointers to table */
  461.         for (j = 0; i--; j++) {
  462.         spectab[j] = tabptr;
  463.         tabptr += strlen(tabptr) + 1;
  464.         }
  465.  
  466.     } else {    /* didn't find table - allocate a null one */
  467.  
  468.         error (!FATAL, "Can't open special character file: %s", specfile);
  469.         spectab = (char **) malloc(2 * sizeof(char*));
  470.         spectab[0] = malloc (2);
  471.         spectab[1] = spectab[0] + 1;
  472.         *spectab[0] = '\0';
  473.         *spectab[1] = '\0';
  474.     }
  475. }
  476.  
  477.  
  478.         /* just got "p#" command.  print the current page and */
  479. t_page(n)    /* do whatever new page functions */
  480. {
  481.     long ftell();
  482.     int c, m, i;
  483.     char buf[100], *bp;
  484.  
  485.     pgnum[np++] = n;
  486.     pgadr[np] = ftell(fp);
  487.     if (np > npmax)
  488.         npmax = np;
  489.     if (output == 0) {
  490.         output = in_olist(n);
  491.         t_init(1);
  492.         return;
  493.     }
  494.  
  495.     putpage();
  496.     fflush(stdout);
  497.  
  498.     if (clearsc) putchar(' ');
  499.     if (keepon) {
  500.         t_init(1);
  501.         return;
  502.     }
  503.   next:
  504.     for (bp = buf; (*bp = readch()); )
  505.         if (*bp++ == '\n')
  506.             break;
  507.     *bp = 0;
  508.     switch (buf[0]) {
  509.     case 0:
  510.         done();
  511.         break;
  512.     case '\n':
  513.         output = in_olist(n);
  514.         t_init(1);
  515.         return;
  516.     case '-':
  517.     case 'p':
  518.         m = atoi(&buf[1]) + 1;
  519.         if (fp == stdin) {
  520.             fputs("you can't; it's not a file\n", stderr);
  521.             break;
  522.         }
  523.         if (np - m <= 0) {
  524.             fputs("too far back\n", stderr);
  525.             break;
  526.         }
  527.         np -= m;
  528.         fseek(fp, pgadr[np], 0);
  529.         output = 1;
  530.         t_init(1);
  531.         return;
  532.     case '0': case '1': case '2': case '3': case '4':
  533.     case '5': case '6': case '7': case '8': case '9':
  534.         m = atoi(&buf[0]);
  535.         for (i = 0; i < npmax; i++)
  536.             if (m == pgnum[i])
  537.                 break;
  538.         if (i >= npmax || fp == stdin) {
  539.             fputs("you can't\n", stderr);
  540.             break;
  541.         }
  542.         np = i + 1;
  543.         fseek(fp, pgadr[np], 0);
  544.         output = 1;
  545.         t_init(1);
  546.         return;
  547.     case 'o':
  548.         outlist(&buf[1]);
  549.         output = 0;
  550.         t_init(1);
  551.         return;
  552.     case '?':
  553.         fputs("p    print this page again\n", stderr);
  554.         fputs("-n    go back n pages\n", stderr);
  555.         fputs("n    print page n (previously printed)\n", stderr);
  556.         fputs("o...    set the -o output list to ...\n", stderr);
  557.         break;
  558.     default:
  559.         fputs("?\n", stderr);
  560.         break;
  561.     }
  562.     goto next;
  563. }
  564.  
  565.             /* print the contents of the current page.  puts out */
  566. putpage()        /* only the part of the page that's been written on */
  567. {            /* unless "margin" is set. */
  568.     int i, j, k;
  569.  
  570.     fflush(stdout);
  571.     if (margin) minv = minh = 0;
  572.     for (i = minv; i <= maxv; i++) {
  573.         for (k = maxh; pagebuf[i][k] == ' '; k--)
  574.             ;
  575.         if (k > minh + linelen)
  576.             k = minh + linelen;
  577.         for (j = minh; j <= k; j++)
  578.             putchar(pagebuf[i][j]);
  579.         putchar('\n');
  580.     }
  581.     fflush(stdout);
  582. }
  583.  
  584.  
  585. t_text(s)        /* print string s as text */
  586. char *s;
  587. {
  588.     int c;
  589.     char str[100];
  590.  
  591.     if (!output)
  592.         return;
  593.     while ((c = *s++) != '\n') {
  594.         if (c == '\\') {
  595.             switch (c = *s++) {
  596.             case '\\':
  597.             case 'e':
  598.                 put1('\\');
  599.                 break;
  600.             case '(':
  601.                 str[0] = *s++;
  602.                 str[1] = *s++;
  603.                 str[2] = '\0';
  604.                 put1s(str);
  605.                 break;
  606.             }
  607.         } else {
  608.             put1(c);
  609.         }
  610.         hmot((int)hscale);
  611.     }
  612. }
  613.  
  614.  
  615. put1s(s)    /* s is a funny char name */
  616. char *s;
  617. {
  618.     int i;
  619.     char *p;
  620.     static char prev[10] = "";
  621.     static int previ;
  622.  
  623.     if (!output)
  624.         return;
  625.     if (strcmp(s, prev) != 0) {
  626.         previ = -1;
  627.         for (i = 0; *spectab[i] != '\0'; i += 2)
  628.             if (strcmp(spectab[i], s) == 0) {
  629.                 strcpy(prev, s);
  630.                 previ = i;
  631.                 break;
  632.             }
  633.     }
  634.     if (previ >= 0) {
  635.         for (hmot((int)-hscale), p = spectab[previ+1]; *p; p++) {
  636.             hmot((int)hscale);
  637.             store(*p);
  638.         }
  639.     } else
  640.         prev[0] = '\0';
  641. }
  642.  
  643.  
  644. put1(c)            /* output char c */
  645. int c;
  646. {
  647.     if (!output)
  648.         return;
  649.     store(c);
  650. }
  651.  
  652.  
  653. done()
  654. {
  655.     output = 1;
  656.     putpage();
  657.     fflush(stdout);
  658.     exit(0);
  659. }
  660.  
  661.  
  662. readch ()
  663. {
  664.     int c;
  665.     static FILE *rcf;
  666.     static nbol;    /* 0 if at beginning of a line */
  667.  
  668.     if (rcf == NULL) {
  669.         rcf = fopen ("/dev/tty", "r");
  670.         setbuf (rcf, NULL);
  671.     }
  672.  
  673.     if (!nbol)
  674.         fprintf (stderr, "dterm: ");    /* issue prompt */
  675.     if ((c = getc (rcf)) == EOF)
  676.         return 0;
  677.     nbol = (c != '\n');
  678.     return c;
  679. }
  680.  
  681.  
  682. store(c)        /* put 'c' in the page at (hpos, vpos) */
  683. {
  684.     register int i;
  685.     register int j;
  686.  
  687.  
  688.     i = hpos / hscale;    /* scale the position to page coordinates */
  689.     j = vpos / vscale;
  690.  
  691.     if (i >= PGWIDTH) i = PGWIDTH - 1;    /* don't go over the edge */
  692.     else if (i < 0) i = 0;
  693.     if (j >= PGHEIGHT) j = PGHEIGHT - 1;
  694.     else if (j < 0) j = 0;
  695.  
  696.     pagebuf[j][i] = c;        /* write the character */
  697.  
  698.     if (i > maxh) maxh = i;        /* update the page bounds */
  699.     if (i < minh) minh = i;
  700.     if (j > maxv) maxv = j;
  701.     if (j < minv) minv = j;
  702. }
  703.  
  704.  
  705. drawline(dx, dy)    /* draw line from here to dx, dy using s */
  706. int dx, dy;
  707. {
  708.     register int xd;
  709.     register int yd;
  710.     register int i;
  711.     register int numdots;
  712.     int dirmot, perp;
  713.     int motincr, perpincr;
  714.     int ohpos, ovpos;
  715.     float val, slope;
  716.     float incrway;
  717.  
  718.     ohpos = hpos;
  719.     ovpos = vpos;
  720.     xd = dx / DP;
  721.     yd = dy / DP;
  722.     if (xd == 0) {
  723.         numdots = abs (yd);
  724.         numdots = min(numdots, maxdots);
  725.         motincr = DP * sgn (yd);
  726.         put1('|');
  727.         for (i = 0; i < numdots; i++) {
  728.             vmot(motincr);
  729.             put1('|');
  730.         }
  731.     } else
  732.     if (yd == 0) {
  733.         numdots = abs (xd);
  734.         numdots = min(numdots, maxdots);
  735.         motincr = DP * sgn (xd);
  736.         put1('-');
  737.         for (i = 0; i < numdots; i++) {
  738.             hmot(motincr);
  739.             put1('-');
  740.         }
  741.     } else {
  742.         if (abs (xd) > abs (yd)) {
  743.         val = slope = (float) xd/yd;
  744.         numdots = abs (xd);
  745.         dirmot = 'h';
  746.         perp = 'v';
  747.         motincr = DP * sgn (xd);
  748.         perpincr = DP * sgn (yd);
  749.         } else {
  750.         val = slope = (float) yd/xd;
  751.         numdots = abs (yd);
  752.         dirmot = 'v';
  753.         perp = 'h';
  754.         motincr = DP * sgn (yd);
  755.         perpincr = DP * sgn (xd);
  756.         }
  757.         numdots = min(numdots, maxdots);
  758.         incrway = sgn ((int) slope);
  759.         put1('*');
  760.         for (i = 0; i < numdots; i++) {
  761.         val -= incrway;
  762.         if (dirmot == 'h')
  763.             hmot(motincr);
  764.         else
  765.             vmot(motincr);
  766.         if (val * slope < 0) {
  767.             if (perp == 'h')
  768.                 hmot(perpincr);
  769.             else
  770.                 vmot(perpincr);
  771.             val += slope;
  772.         }
  773.         put1('*');
  774.         }
  775.     }
  776.     hgoto(ohpos + dx);
  777.     vgoto(ovpos + dy);
  778. }
  779.  
  780.  
  781. drawwig(s, poly)    /* draw wiggly line or polygon, if "poly" set */
  782. char *s;
  783. int poly;
  784. {
  785.     int x[50], y[50], xp, yp, pxp, pyp;
  786.     float t1, t2, t3, w;
  787.     int i, j, numdots, N;
  788.     char temp[50], *p, *getstr();
  789.  
  790.     p = s;
  791.     for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]);) {
  792.         x[N] = atoi(temp);
  793.         p = getstr(p, temp);
  794.         y[N++] = atoi(temp);
  795.     }
  796.     if (poly) {
  797.         for (i = 2; i < N; i++)
  798.             drawline(x[i], y[i]);
  799.         return;
  800.     }
  801.     x[0] = x[1] = hpos;
  802.     y[0] = y[1] = vpos;
  803.     for (i = 1; i < N; i++) {
  804.         x[i+1] += x[i];
  805.         y[i+1] += y[i];
  806.     }
  807.     x[N] = x[N-1];
  808.     y[N] = y[N-1];
  809.     pxp = pyp = -9999;
  810.     for (i = 0; i < N-1; i++) {    /* interval */
  811.         numdots = (dist(x[i], y[i], x[i+1], y[i+1])
  812.                  + dist(x[i+1], y[i+1], x[i+2], y[i+2])) / 2;
  813.         numdots /= DP;
  814.         numdots = min(numdots, maxdots);
  815.         for (j = 0; j < numdots; j++) {    /* points within */
  816.             w = (float) j / numdots;
  817.             t1 = 0.5 * w * w;
  818.             w = w - 0.5;
  819.             t2 = 0.75 - w * w;
  820.             w = w - 0.5;
  821.             t3 = 0.5 * w * w;
  822.             xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5;
  823.             yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5;
  824.             if (xp != pxp || yp != pyp) {
  825.                 hgoto(xp);
  826.                 vgoto(yp);
  827.                 put1('*');
  828.                 pxp = xp;
  829.                 pyp = yp;
  830.             }
  831.         }
  832.     }
  833. }
  834.  
  835.  
  836. /* copy next non-blank string from p to temp, update p */
  837.  
  838. char *getstr(p, temp)
  839. char *p, *temp;
  840. {
  841.     while (*p == ' ' || *p == '\t' || *p == '\n')
  842.         p++;
  843.     if (*p == '\0') {
  844.         temp[0] = 0;
  845.         return(NULL);
  846.     }
  847.     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
  848.         *temp++ = *p++;
  849.     *temp = '\0';
  850.     return(p);
  851. }
  852.  
  853.  
  854. drawcirc(d)
  855. {
  856.     int xc, yc;
  857.  
  858.     xc = hpos;
  859.     yc = vpos;
  860.     conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2);
  861.     hgoto(xc + d);    /* circle goes to right side */
  862.     vgoto(yc);
  863. }
  864.  
  865.  
  866. dist(x1, y1, x2, y2)    /* integer distance from x1,y1 to x2,y2 */
  867. {
  868.     float dx, dy;
  869.  
  870.     dx = x2 - x1;
  871.     dy = y2 - y1;
  872.     return sqrt(dx*dx + dy*dy) + 0.5;
  873. }
  874.  
  875.  
  876. drawarc(dx1, dy1, dx2, dy2)
  877. {
  878.     int x0, y0, x2, y2, r;
  879.  
  880.     x0 = hpos + dx1;    /* center */
  881.     y0 = vpos + dy1;
  882.     x2 = x0 + dx2;    /* "to" */
  883.     y2 = y0 + dy2;
  884.     r = sqrt((float) dx1 * dx1 + (float) dy1 * dy1) + 0.5;
  885.     conicarc(x0, -y0, hpos, -vpos, x2, -y2, r, r);
  886. }
  887.  
  888.  
  889. drawellip(a, b)
  890. {
  891.     int xc, yc;
  892.  
  893.     xc = hpos;
  894.     yc = vpos;
  895.     conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2);
  896.     hgoto(xc + a);
  897.     vgoto(yc);
  898. }
  899.  
  900.  
  901. conicarc(x, y, x0, y0, x1, y1, a, b)
  902. {
  903.         /* based on Bresenham, CACM Feb 77, pp 102-3 by Chris Van Wyk */
  904.         /* capitalized vars are an internal reference frame */
  905.     long dotcount = 0;
  906.     int    xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt,
  907.         M1x, M1y, M2x, M2y, M3x, M3y,
  908.         Q, move, Xc, Yc;
  909.     int ox1, oy1;
  910.     long    delta;
  911.     float    xc, yc;
  912.     float    radius, slope;
  913.     float    xstep, ystep;
  914.  
  915.     ox1 = x1;
  916.     oy1 = y1;
  917.     if (a != b)    /* an arc of an ellipse; internally, think of circle */
  918.         if (a > b) {
  919.             xstep = (float)a / b;
  920.             ystep = 1;
  921.             radius = b;
  922.         } else {
  923.             xstep = 1;
  924.             ystep = (float)b / a;
  925.             radius = a;
  926.         } 
  927.     else {
  928.         /* a circular arc; radius computed from center and first point */    
  929.         xstep = ystep = 1;
  930.         radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y)));
  931.     }
  932.  
  933.     xc = x0;
  934.     yc = y0;
  935.     /* now, use start and end point locations to figure out
  936.     the angle at which start and end happen; use these
  937.     angles with known radius to figure out where start
  938.     and end should be
  939.     */
  940.     slope = atan2((double)(y0 - y), (double)(x0 - x) );
  941.     if (slope == 0.0 && x0 < x)
  942.         slope = 3.14159265;
  943.     x0 = x + radius * cos(slope) + 0.5;
  944.     y0 = y + radius * sin(slope) + 0.5;
  945.     slope = atan2((double)(y1 - y), (double)(x1 - x));
  946.     if (slope == 0.0 && x1 < x)
  947.         slope = 3.14159265;
  948.     x1 = x + radius * cos(slope) + 0.5;
  949.     y1 = y + radius * sin(slope) + 0.5;
  950.     /* step 2: translate to zero-centered circle */
  951.     xs = x0 - x;
  952.     ys = y0 - y;
  953.     xt = x1 - x;
  954.     yt = y1 - y;
  955.     /* step 3: normalize to first quadrant */
  956.     if (xs < 0)
  957.         if (ys < 0) {
  958.             Xs = abs(ys);
  959.             Ys = abs(xs);
  960.             qs = 3;
  961.             M1x = 0;
  962.             M1y = -1;
  963.             M2x = 1;
  964.             M2y = -1;
  965.             M3x = 1;
  966.             M3y = 0;
  967.         } else {
  968.             Xs = abs(xs);
  969.             Ys = abs(ys);
  970.             qs = 2;
  971.             M1x = -1;
  972.             M1y = 0;
  973.             M2x = -1;
  974.             M2y = -1;
  975.             M3x = 0;
  976.             M3y = -1;
  977.         } 
  978.     else if (ys < 0) {
  979.         Xs = abs(xs);
  980.         Ys = abs(ys);
  981.         qs = 0;
  982.         M1x = 1;
  983.         M1y = 0;
  984.         M2x = 1;
  985.         M2y = 1;
  986.         M3x = 0;
  987.         M3y = 1;
  988.     } else {
  989.         Xs = abs(ys);
  990.         Ys = abs(xs);
  991.         qs = 1;
  992.         M1x = 0;
  993.         M1y = 1;
  994.         M2x = -1;
  995.         M2y = 1;
  996.         M3x = -1;
  997.         M3y = 0;
  998.     }
  999.  
  1000.     Xc = Xs;
  1001.     Yc = Ys;
  1002.     if (xt < 0)
  1003.         if (yt < 0) {
  1004.             Xt = abs(yt);
  1005.             Yt = abs(xt);
  1006.             qt = 3;
  1007.         } else {
  1008.             Xt = abs(xt);
  1009.             Yt = abs(yt);
  1010.             qt = 2;
  1011.         } 
  1012.     else if (yt < 0) {
  1013.         Xt = abs(xt);
  1014.         Yt = abs(yt);
  1015.         qt = 0;
  1016.     } else {
  1017.         Xt = abs(yt);
  1018.         Yt = abs(xt);
  1019.         qt = 1;
  1020.     }
  1021.  
  1022.         /* step 4: calculate number of quadrant crossings */
  1023.     if (((4 + qt - qs) % 4 == 0) && (Xt <= Xs) && (Yt >= Ys))
  1024.         Q = 3;
  1025.     else
  1026.         Q = (4 + qt - qs) % 4 - 1;
  1027.         /* step 5: calculate initial decision difference */
  1028.     delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
  1029.                 /* here begins the work of drawing. */
  1030.     while ((Q >= 0) || ((Q > -2) && ((Xt > Xc) && (Yt < Yc)))) {
  1031.         if (dotcount++ % DP == 0) {
  1032.             hgoto((int)xc);
  1033.             vmot(-vpos-((int)yc));
  1034.             put1('*');
  1035.         }
  1036.         if (Yc < 0.5) {
  1037.             /* reinitialize */
  1038.             Xs = Xc = 0;
  1039.             Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys)));
  1040.             delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
  1041.             Q--;
  1042.             M1x = M3x;
  1043.             M1y = M3y;
  1044.              {
  1045.                 int    T;
  1046.                 T = M2y;
  1047.                 M2y = M2x;
  1048.                 M2x = -T;
  1049.                 T = M3y;
  1050.                 M3y = M3x;
  1051.                 M3x = -T;
  1052.             }
  1053.         } else {
  1054.             if (delta <= 0)
  1055.                 if (2 * delta + 2 * Yc - 1 <= 0)
  1056.                     move = 1;
  1057.                 else
  1058.                     move = 2;
  1059.             else if (2 * delta - 2 * Xc - 1 <= 0)
  1060.                 move = 2;
  1061.             else
  1062.                 move = 3;
  1063.             switch (move) {
  1064.             case 1:
  1065.                 Xc++;
  1066.                 delta += 2 * Xc + 1;
  1067.                 xc += M1x * xstep;
  1068.                 yc += M1y * ystep;
  1069.                 break;
  1070.             case 2:
  1071.                 Xc++;
  1072.                 Yc--;
  1073.                 delta += 2 * Xc - 2 * Yc + 2;
  1074.                 xc += M2x * xstep;
  1075.                 yc += M2y * ystep;
  1076.                 break;
  1077.             case 3:
  1078.                 Yc--;
  1079.                 delta -= 2 * Yc + 1;
  1080.                 xc += M3x * xstep;
  1081.                 yc += M3y * ystep;
  1082.                 break;
  1083.             }
  1084.         }
  1085.     }
  1086.     drawline((int)xc-ox1,(int)yc-oy1);
  1087. }
  1088.